using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using TangLiveRecorder.Models;

namespace TangLiveRecorder.Services
{
    /// <summary>
    /// 录制服务类
    /// 负责管理ffmpeg录制进程，提供录制任务的启动、停止和状态管理功能
    /// </summary>
    public class RecordingService
    {
        /// <summary>
        /// 录制任务信息
        /// </summary>
        public class RecordingTask
        {
            /// <summary>
            /// 直播信息
            /// </summary>
            public LiveInfo LiveInfo { get; set; }

            /// <summary>
            /// ffmpeg进程
            /// </summary>
            public Process Process { get; set; }

            /// <summary>
            /// 录制开始时间
            /// </summary>
            public DateTime StartTime { get; set; }

            /// <summary>
            /// 输出文件路径
            /// </summary>
            public string OutputFilePath { get; set; }

            /// <summary>
            /// 取消令牌源
            /// </summary>
            public CancellationTokenSource CancellationTokenSource { get; set; }
        }

        /// <summary>
        /// 当前录制任务字典，键为直播GUID
        /// </summary>
        private readonly ConcurrentDictionary<string, RecordingTask> _recordingTasks;

        /// <summary>
        /// 录制输出根目录
        /// </summary>
        private readonly string _recordingDirectory;

        /// <summary>
        /// 数据持久化服务
        /// </summary>
        private readonly DataPersistenceService _dataPersistenceService;

        /// <summary>
        /// 初始化录制服务
        /// </summary>
        /// <param name="dataPersistenceService">数据持久化服务</param>
        public RecordingService(DataPersistenceService dataPersistenceService)
        {
            _recordingTasks = new ConcurrentDictionary<string, RecordingTask>();
            _dataPersistenceService = dataPersistenceService;

            // 设置录制输出目录
            var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            _recordingDirectory = Path.Combine(documentsPath, "TangLiveRecorder", "Recordings");

            // 确保录制目录存在
            if (!Directory.Exists(_recordingDirectory))
            {
                Directory.CreateDirectory(_recordingDirectory);
            }
        }

        /// <summary>
        /// 启动录制
        /// </summary>
        /// <param name="liveInfo">直播信息</param>
        /// <param name="streamUrl">直播流地址</param>
        /// <returns>是否启动成功</returns>
        public async Task<bool> StartRecordingAsync(LiveInfo liveInfo, string streamUrl)
        {
            try
            {
                // 检查是否已经在录制
                if (_recordingTasks.ContainsKey(liveInfo.Guid))
                {
                    Data.AddLog($"[录制服务] {liveInfo.Name} 已在录制中，跳过启动");
                    return false;
                }

                // 创建录制文件路径
                var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
                var safeFileName = GetSafeFileName(liveInfo.Name);
                var fileName = $"{safeFileName}_{timestamp}.mp4";
                var outputPath = Path.Combine(_recordingDirectory, fileName);

                // 创建ffmpeg进程
                var process = CreateFFmpegProcess(streamUrl, outputPath);
                var cancellationTokenSource = new CancellationTokenSource();

                // 创建录制任务
                var recordingTask = new RecordingTask
                {
                    LiveInfo = liveInfo,
                    Process = process,
                    StartTime = DateTime.Now,
                    OutputFilePath = outputPath,
                    CancellationTokenSource = cancellationTokenSource
                };

                // 启动进程
                process.Start();

                // 开始异步读取标准输出和错误输出
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                process.OutputDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                    {
                        Data.AddLog($"[FFmpeg输出] {liveInfo.Name}: {e.Data}");
                    }
                };

                process.ErrorDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                    {
                        Data.AddLog($"[FFmpeg] {liveInfo.Name}: {e.Data}");
                    }
                };

                // 添加到录制任务列表
                _recordingTasks.TryAdd(liveInfo.Guid, recordingTask);

                // 异步监控进程状态
                _ = Task.Run(() => MonitorRecordingProcess(recordingTask), cancellationTokenSource.Token);

                Data.AddLog($"[录制服务] 开始录制 {liveInfo.Name}，输出文件: {fileName}");
                return true;
            }
            catch (Exception ex)
            {
                Data.AddLog($"[录制服务] 启动录制失败 {liveInfo.Name}: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 停止录制
        /// </summary>
        /// <param name="liveGuid">直播GUID</param>
        /// <returns>是否停止成功</returns>
        public async Task<bool> StopRecordingAsync(string liveGuid)
        {
            try
            {
                if (!_recordingTasks.TryRemove(liveGuid, out var recordingTask))
                {
                    Data.AddLog($"[录制服务] 未找到录制任务: {liveGuid}");
                    return false;
                }

                // 取消监控任务
                recordingTask.CancellationTokenSource?.Cancel();

                // 优雅停止ffmpeg进程
                if (recordingTask.Process != null && !recordingTask.Process.HasExited)
                {
                    // 发送'q'命令优雅停止ffmpeg
                    try
                    {
                        recordingTask.Process.StandardInput.WriteLine("q");
                        recordingTask.Process.StandardInput.Flush();

                        // 等待进程退出，最多等待5秒
                        if (!recordingTask.Process.WaitForExit(5000))
                        {
                            recordingTask.Process.Kill();
                        }
                    }
                    catch
                    {
                        recordingTask.Process.Kill();
                    }
                }

                // 计算录制时长
                var duration = DateTime.Now - recordingTask.StartTime;

                // 保存录制文件信息
                await SaveRecordingFileInfo(recordingTask, duration);

                Data.AddLog($"[录制服务] 停止录制 {recordingTask.LiveInfo.Name}，时长: {duration:hh\\:mm\\:ss}");
                return true;
            }
            catch (Exception ex)
            {
                Data.AddLog($"[录制服务] 停止录制失败: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 停止所有录制
        /// </summary>
        public async Task StopAllRecordingsAsync()
        {
            var tasks = _recordingTasks.Keys.ToList();
            foreach (var liveGuid in tasks)
            {
                await StopRecordingAsync(liveGuid);
            }
        }

        /// <summary>
        /// 获取当前录制任务列表
        /// </summary>
        /// <returns>录制任务信息列表</returns>
        public List<(string LiveName, string FileName, TimeSpan Duration)> GetRecordingTasks()
        {
            return _recordingTasks.Values.Select(task => (
                task.LiveInfo.Name,
                Path.GetFileName(task.OutputFilePath),
                DateTime.Now - task.StartTime
            )).ToList();
        }

        /// <summary>
        /// 检查指定直播是否正在录制
        /// </summary>
        /// <param name="liveGuid">直播GUID</param>
        /// <returns>是否正在录制</returns>
        public bool IsRecording(string liveGuid)
        {
            return _recordingTasks.ContainsKey(liveGuid);
        }

        /// <summary>
        /// 创建ffmpeg进程
        /// </summary>
        /// <param name="inputUrl">输入流地址</param>
        /// <param name="outputPath">输出文件路径</param>
        /// <returns>ffmpeg进程</returns>
        private Process CreateFFmpegProcess(string inputUrl, string outputPath)
        {
            // 改进的ffmpeg参数，添加更多稳定性选项
            var arguments = $"-i \"{inputUrl}\" -c copy -avoid_negative_ts make_zero -fflags +genpts -f mp4 \"{outputPath}\"";

            var processStartInfo = new ProcessStartInfo
            {
                FileName = "ffmpeg",
                Arguments = arguments,
                UseShellExecute = false,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                CreateNoWindow = true,
                StandardInputEncoding = System.Text.Encoding.UTF8,
                StandardOutputEncoding = System.Text.Encoding.UTF8,
                StandardErrorEncoding = System.Text.Encoding.UTF8
            };

            Data.AddLog($"[录制服务] FFmpeg命令: ffmpeg {arguments}");
            return new Process { StartInfo = processStartInfo };
        }

        /// <summary>
        /// 监控录制进程状态
        /// </summary>
        /// <param name="recordingTask">录制任务</param>
        private async Task MonitorRecordingProcess(RecordingTask recordingTask)
        {
            try
            {
                await recordingTask.Process.WaitForExitAsync(recordingTask.CancellationTokenSource.Token);

                // 进程退出，从任务列表中移除
                _recordingTasks.TryRemove(recordingTask.LiveInfo.Guid, out _);

                var duration = DateTime.Now - recordingTask.StartTime;
                Data.AddLog($"[录制服务] 录制进程退出 {recordingTask.LiveInfo.Name}，时长: {duration:hh\\:mm\\:ss}");

                // 保存录制文件信息
                await SaveRecordingFileInfo(recordingTask, duration);
            }
            catch (OperationCanceledException)
            {
                // 正常取消，不需要处理
            }
            catch (Exception ex)
            {
                Data.AddLog($"[录制服务] 监控录制进程异常: {ex.Message}");
            }
        }

        /// <summary>
        /// 保存录制文件信息
        /// </summary>
        /// <param name="recordingTask">录制任务</param>
        /// <param name="duration">录制时长</param>
        private async Task SaveRecordingFileInfo(RecordingTask recordingTask, TimeSpan duration)
        {
            try
            {
                // 检查文件是否存在且有内容
                if (File.Exists(recordingTask.OutputFilePath))
                {
                    var fileInfo = new FileInfo(recordingTask.OutputFilePath);
                    {
                        // 创建文件信息对象
                        var fileInfoModel = new FileInfos
                        {
                            Guid = System.Guid.NewGuid().ToString(),
                            Name = recordingTask.LiveInfo.Name,
                            Path = recordingTask.OutputFilePath,
                            Size = fileInfo.Length,
                            CreatedTime = DateTime.Now,
                        };

                        Data.AddFile(fileInfoModel);
                        //// 添加到文件列表并保存
                        //var allFiles = Data.GetAllFiles() ?? new List<FileInfos>();
                        //allFiles.Add(fileInfoModel);

                        //await _dataPersistenceService.SaveFilesAsync(allFiles);

                        Data.AddLog($"[录制服务] 录制文件已保存: {Path.GetFileName(recordingTask.OutputFilePath)}");
                    }
                }
            }
            catch (Exception ex)
            {
                Data.AddLog($"[录制服务] 保存录制文件信息失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取安全的文件名
        /// </summary>
        /// <param name="fileName">原始文件名</param>
        /// <returns>安全的文件名</returns>
        private string GetSafeFileName(string fileName)
        {
            if (string.IsNullOrWhiteSpace(fileName))
                return "Unknown";

            var invalidChars = Path.GetInvalidFileNameChars();
            var safeFileName = new string(fileName.Where(c => !invalidChars.Contains(c)).ToArray());

            return string.IsNullOrWhiteSpace(safeFileName) ? "Unknown" : safeFileName;
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public async Task DisposeAsync()
        {
            await StopAllRecordingsAsync();
        }
    }
}